﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Linq.Expressions;

namespace Ue.CQRS.Samples.Repositories
{
    public class CacheRepository<T> : IRepository<T>
    {
        public static ConcurrentDictionary<Guid, T> Caches = new ConcurrentDictionary<Guid, T>();

        public T this[Guid key]
        {
            get
            {
                return this.ContainsKey(key) ? Caches[key] : default(T);
            }
            set
            {
                if (this.ContainsKey(key))
                {
                    Caches[key] = value;
                }
                else
                {
                    Caches.GetOrAdd(key, value);
                }
            }
        }

        public T GetOrAdd(Guid key, T entity)
        {
            return Caches.GetOrAdd(key, entity);
        }

        public T GetOrAdd(Guid key, Func<Guid, T> addEntityFactory)
        {
            return Caches.GetOrAdd(key, addEntityFactory);
        }

        public void AddOrUpdate(Guid key, T entity)
        {
            Caches.AddOrUpdate(key, entity, (k, e) => entity);
        }

        public void AddOrUpdate(Guid key, Func<Guid, T> entityFactory)
        {
            Caches.AddOrUpdate(key, entityFactory, (k, e) => entityFactory(k));
        }

        public void AddOrUpdate(Guid key, Func<Guid, T> addEntityFactory, Func<Guid, T, T> updateEntityFactory)
        {
            Caches.AddOrUpdate(key, addEntityFactory, updateEntityFactory);
        }

        public void Remove(Guid key)
        {
            T value=default(T);

            Caches.TryRemove(key, out value);
        }

        public bool ContainsKey(Guid key)
        {
            return Caches.ContainsKey(key);
        }

        public IEnumerable<T> FindBy(Expression<Func<T,bool>> predicate)
        {
            return Caches.Values.Where(predicate.Compile());
        }

        public IEnumerable<T> FindBy(Expression<Func<T,bool>> predicate, int skip, int count)
        {
            return this.FindBy(predicate).Skip(skip).Take(count);
        }

        public IEnumerable<T> FindAll()
        {
            return Caches.Values;
        }
    }
}
